namespace SubhadraSolutions.Sharp.Utils.Algorithms
{
    using SubhadraSolutions.Sharp.Utils.Validation;
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;

    public static class SortHelper
    {
        #region Methods

        public static void QuickSort<T>(this IList<T> list, int left, int right,
            IComparer<T> comparer,
            bool assending)
        {
            do
            {
                int a = left;
                int b = right;
                int num3 = a + ((b - a) >> 1);
                swapIfGreaterWithItems(list, comparer, a, num3, assending);
                swapIfGreaterWithItems(list, comparer, a, b, assending);
                swapIfGreaterWithItems(list, comparer, num3, b, assending);
                T y = list[num3];
                do
                {
                    while ((assending
                        ? comparer.Compare(list[a], y)
                        : -(comparer.Compare(list[a], y))) < 0)
                    {
                        a++;
                    }
                    while ((assending
                        ? comparer.Compare(y, list[b])
                        : -(comparer.Compare(y, list[b]))) < 0)
                    {
                        b--;
                    }
                    if (a > b)
                    {
                        break;
                    }
                    if (a < b)
                    {
                        T local2 = list[a];
                        list[a] = list[b];
                        list[b] = local2;
                    }
                    a++;
                    b--;
                } while (a <= b);
                if ((b - left) <= (right - a))
                {
                    if (left < b)
                    {
                        QuickSort(list, left, b, comparer, assending);
                    }
                    left = a;
                }
                else
                {
                    if (a < right)
                    {
                        QuickSort(list, a, right, comparer, assending);
                    }
                    right = b;
                }
            } while (left < right);
        }

        public static void QuickSort<T>(this IList<T> list, bool assending)
        {
            QuickSort(list, 0, list.Count, null, assending);
        }

        public static void QuickSort<T>(this IList<T> list, IComparer<T> comparer, bool assending)
        {
            QuickSort(list, 0, list.Count, comparer, assending);
        }

        public static void QuickSort<T>(this IList<T> list, Comparison<T> comparison, bool assending)
        {
            Guard.ArgumentNotNull(comparison, "comparison");
            IComparer<T> comparer = new DelegateBasedComparer<T>(comparison);
            QuickSort(list, comparer, assending);
        }

        public static void QuickSort<T>(this IList<T> list, int index, int length, bool assending)
        {
            if (length > 0)
            {
                Comparer<T> comparer = Comparer<T>.Default;
                try
                {
                    QuickSort(list, index, index + (length - 1), comparer, assending);
                }
                catch (IndexOutOfRangeException)
                {
                    var values = new object[3];
                    values[1] = typeof(T).Name;
                    values[2] = comparer;
                    throw;
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    throw;
                }
            }
        }

        private static void swapIfGreaterWithItems<T>(IList<T> list, IComparer<T> comparer, int a,
            int b, bool assending)
        {
            if ((a != b) &&
                ((assending
                    ? comparer.Compare(list[a], list[b])
                    : -(comparer.Compare(list[a], list[b]))) > 0))
            {
                T local = list[a];
                list[a] = list[b];
                list[b] = local;
            }
        }

        #endregion Methods
    }
}